﻿package baseEngine.core
{
    import __AS3__.vec.*;
    import baseEngine.system.*;
    import flash.geom.*;
    import frEngine.*;
    import frEngine.core.lenses.*;
    import frEngine.event.*;

    public class Camera3D extends Pivot3D
    {
        private var _near:Number;
        private var _far:Number;
        private var _fieldOfView:Number;
        private var _zoom:Number;
        protected var _aspect:Number;
        private var _view:Matrix3D;
        private var _projection:Matrix3D;
        private var _viewProjection:Matrix3D;
        private var _viewport:Rectangle;
        private var _canvasSize:Point;
        public var clipRectangle:Rectangle;
        private var _lens:LensBase;
        private var _viewQuaternion:Vector3D;
        protected var _basePos:Vector3D;
        protected var _shakePos:Vector3D;
        public static const FieldChange_flag:int = 1 << 5;

        public function Camera3D(param1:String = "", param2:Number = 75, param3:LensBase = null, param4:Number = 1, param5:Number = 10000)
        {
            this._viewQuaternion = new Vector3D();
            this._basePos = new Vector3D();
            this._shakePos = new Vector3D();
            super(param1);
            this._lens = param3;
            this._near = param4;
            this._far = param5;
            this._view = new Matrix3D();
            this._projection = new Matrix3D();
            this._viewProjection = new Matrix3D();
            this.aspectRatio = this._aspect;
            this.fieldOfView = param2;
            this.updateProjectionMatrix();
            return;
        }// end function

        override public function rotateX(param1:Number, param2:Boolean = true, param3:Vector3D = null) : void
        {
            super.rotateX(param1, param2, param3);
            this.updateBaseByTransform();
            return;
        }// end function

        override public function rotateY(param1:Number, param2:Boolean = true, param3:Vector3D = null) : void
        {
            super.rotateY(param1, param2, param3);
            this.updateBaseByTransform();
            return;
        }// end function

        override public function rotateZ(param1:Number, param2:Boolean = true, param3:Vector3D = null) : void
        {
            super.rotateZ(param1, param2, param3);
            this.updateBaseByTransform();
            return;
        }// end function

        private function updateBaseByTransform() : void
        {
            var _loc_1:* = this.transform.position;
            this.setBasePosValue(_loc_1.x, _loc_1.y, _loc_1.z);
            return;
        }// end function

        override public function translateX(param1:Number, param2:Boolean = true) : void
        {
            super.translateX(param1, param2);
            this.updateBaseByTransform();
            return;
        }// end function

        override public function translateY(param1:Number, param2:Boolean = true) : void
        {
            super.translateY(param1, param2);
            this.updateBaseByTransform();
            return;
        }// end function

        override public function translateZ(param1:Number, param2:Boolean = true) : void
        {
            super.translateZ(param1, param2);
            this.updateBaseByTransform();
            return;
        }// end function

        public function setBasePosValue(param1:Number, param2:Number, param3:Number) : void
        {
            this._basePos.setTo(param1, param2, param3);
            this.setPosition(param1 + this._shakePos.x, param2 + this._shakePos.y, param3 + this._shakePos.z);
            return;
        }// end function

        public function setShakeValue(param1:Number, param2:Number, param3:Number) : void
        {
            this._shakePos.setTo(param1, param2, param3);
            this.setPosition(param1 + this._basePos.x, param2 + this._basePos.y, param3 + this._basePos.z);
            return;
        }// end function

        override public function addEventListener(param1:String, param2:Function, param3:Boolean = false, param4:int = 0, param5:Boolean = false) : void
        {
            super.addEventListener(param1, param2, param3, param4, param5);
            if (param1 == Engine3dEventName.FieldChange)
            {
                this._eventFlags = this._eventFlags | FieldChange_flag;
            }
            return;
        }// end function

        override public function removeEventListener(param1:String, param2:Function, param3:Boolean = false) : void
        {
            super.removeEventListener(param1, param2, param3);
            if (param1 == Engine3dEventName.FieldChange)
            {
                if (!hasEventListener(param1))
                {
                    this._eventFlags = this._eventFlags | FieldChange_flag;
                    this._eventFlags = this._eventFlags - FieldChange_flag;
                }
            }
            return;
        }// end function

        public function getPointDir(param1:Number, param2:Number, param3:Vector3D = null) : Vector3D
        {
            throw new Error("请覆盖getPointDir方法！");
        }// end function

        public function getPoint3DAtScreenCoords(param1:Vector3D, param2:Vector3D = null) : Vector3D
        {
            if (!param2)
            {
                param2 = new Vector3D();
            }
            var _loc_3:* = this.viewProjection.transformVector(param1);
            var _loc_4:* = Global3D.scene.viewPort;
            var _loc_5:* = _loc_4.width * 0.5;
            var _loc_6:* = _loc_4.height * 0.5;
            param2.x = _loc_3.x / _loc_3.w * _loc_5 + _loc_5 + _loc_4.x;
            param2.y = (-_loc_3.y) / _loc_3.w * _loc_6 + _loc_6 + _loc_4.y;
            param2.z = _loc_3.z;
            param2.w = _loc_3.w;
            return param2;
        }// end function

        public function screenToCamera(param1:Number, param2:Number, param3:Number, param4:Vector3D) : void
        {
            throw new Error("请覆盖screenToCamera方法！");
        }// end function

        final public function get lens() : LensBase
        {
            return this._lens;
        }// end function

        public function getScreenMouseDistance(param1:Number, param2:Number, param3:Vector3D) : Number
        {
            throw new Error("getScreenMouseDistance！");
        }// end function

        final public function set viewPort(param1:Rectangle) : void
        {
            this._viewport = param1;
            this.updateProjectionMatrix();
            return;
        }// end function

        final public function get viewPort() : Rectangle
        {
            return this._viewport;
        }// end function

        final public function set canvasSize(param1:Point) : void
        {
            this._canvasSize = param1;
            this.updateProjectionMatrix();
            return;
        }// end function

        final public function get canvasSize() : Point
        {
            return this._canvasSize;
        }// end function

        public function updateProjectionMatrix() : void
        {
            this.updateProj(this._viewport, this._projection);
            worldTransformChanged = true;
            if (this._eventFlags & FieldChange_flag)
            {
                FrEventDispatcher.instance.proxyDispatchEvent(this, Engine3dEventName.FieldChange);
            }
            return;
        }// end function

        public function get fieldOfView() : Number
        {
            return this._fieldOfView;
        }// end function

        public function set fieldOfView(param1:Number) : void
        {
            if (this._fieldOfView == param1)
            {
                return;
            }
            this._fieldOfView = param1;
            this._zoom = Math.tan(param1 / 2 * Math.PI / 180);
            this.updateProjectionMatrix();
            return;
        }// end function

        public function get zoom() : Number
        {
            return this._zoom;
        }// end function

        public function set zoom(param1:Number) : void
        {
            if (this._zoom == param1)
            {
                return;
            }
            this._zoom = param1;
            this._fieldOfView = Math.atan(param1) * 180 / Math.PI * 2;
            this.updateProjectionMatrix();
            return;
        }// end function

        public function get near() : Number
        {
            return this._near;
        }// end function

        public function set near(param1:Number) : void
        {
            if (param1 <= 0.1)
            {
                param1 = 0.1;
            }
            this._near = param1;
            this.updateProjectionMatrix();
            return;
        }// end function

        public function get far() : Number
        {
            return this._far;
        }// end function

        public function set far(param1:Number) : void
        {
            this._far = param1;
            this.updateProjectionMatrix();
            return;
        }// end function

        final public function get view() : Matrix3D
        {
            return this._view;
        }// end function

        final public function get viewProjection() : Matrix3D
        {
            return this._viewProjection;
        }// end function

        override public function get invWorld() : Matrix3D
        {
            var _loc_3:Vector.<Vector3D> = null;
            var _loc_4:Vector3D = null;
            var _loc_5:Number = NaN;
            var _loc_6:Number = NaN;
            var _loc_1:* = _dirtyInv;
            var _loc_2:* = super.invWorld;
            if (_loc_1)
            {
                this._view.copyFrom(_loc_2);
                this._viewProjection.copyFrom(this._view);
                this._viewProjection.append(this._projection);
                _loc_3 = this._view.decompose(Orientation3D.QUATERNION);
                _loc_4 = _loc_3[1];
                _loc_5 = _loc_4.w * _loc_4.w + _loc_4.x * _loc_4.x + _loc_4.y * _loc_4.y + _loc_4.z * _loc_4.z;
                _loc_6 = 1 / _loc_5;
                _loc_4.x = (-_loc_4.x) * _loc_6;
                _loc_4.y = (-_loc_4.y) * _loc_6;
                _loc_4.z = (-_loc_4.z) * _loc_6;
                _loc_4.w = _loc_4.w * _loc_6;
                this._viewQuaternion = _loc_4;
            }
            return _loc_2;
        }// end function

        final public function get viewQuaternion() : Vector3D
        {
            return this._viewQuaternion;
        }// end function

        final public function get projection() : Matrix3D
        {
            return this._projection;
        }// end function

        final public function set projection(param1:Matrix3D) : void
        {
            this._projection = param1;
            return;
        }// end function

        final public function get aspectRatio() : Number
        {
            return this._aspect;
        }// end function

        final public function set aspectRatio(param1:Number) : void
        {
            this._aspect = param1;
            this.updateProjectionMatrix();
            return;
        }// end function

        override public function dispose(param1:Boolean = true) : void
        {
            if (scene && scene.camera == this)
            {
                scene.camera = null;
            }
            super.dispose(param1);
            return;
        }// end function

        override public function clone() : Pivot3D
        {
            var _loc_1:Pivot3D = null;
            var _loc_2:* = new Camera3D(name);
            _loc_2.copyFrom(this);
            _loc_2.near = this.near;
            _loc_2.far = this.far;
            _loc_2.fieldOfView = this.fieldOfView;
            for each (_loc_1 in children)
            {
                
                if (!_loc_1.lock)
                {
                    _loc_2.addChild(_loc_1.clone());
                }
            }
            return _loc_2;
        }// end function

        public function updateProj(param1:Rectangle, param2:Matrix3D) : void
        {
            throw new Error("请覆盖重写该方法");
        }// end function

    }
}
